home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #221 (1993)(Rhein-Sieg-Soft).zip / Franz PD Disk #221 (1993)(Rhein-Sieg-Soft).adf / Hybris / Hybris.c < prev    next >
C/C++ Source or Header  |  1993-02-15  |  56KB  |  1,480 lines

  1. /* Compileraufruf für DICE: "dcc Hybris.c -oHybris"
  2.  
  3.    Fehler:
  4.  
  5.    - 6er, 7er, ... fehlen total
  6.  
  7.    maybe to do (Schönheitskorrekturen mit Effekt):
  8.    - Änderung von Spalten-/Zeilenzahl/Fallverzögerung durch Joystick
  9.      (siehe Probleme)
  10.  
  11.    Probleme:
  12.  
  13.    - Einstellungen mit Joystick:
  14.      Der (noch in Kommentaren erhaltene) Versuch, die Höhe und Breite des
  15.      Spielfeldes auch per Joystick zu steuern, führte aus ungeklärten
  16.      Gründen dazu, daß nach der ersten derartigen Aktion die Joystick-
  17.      Steuerung blockiert war. Nach Drücken irgendeiner Taste (sogar <SHIFT>
  18.      reichte) war der Joystick wieder frei.
  19.    - Preview-Umschaltung während des Spiels führt zum Löschen der Grafik.
  20.      Entweder, das wird gesperrt (z.Zt. der Fall), oder ich lasse die
  21.      ungültige Grafik im Spiel stehen.
  22.      Letzteres wäre kein Problem, wenn man nicht auch das Preview
  23.      ZUschalten und somit ein größeres Window notwendig machen könnte. Ich
  24.      sehe also im Moment nur die Möglichkeit, die Preview-Schaltung während
  25.      des Spiels lahmzulegen.
  26.      Eigentlich wäre es wünschenswert, auch während des Spiels das Preview
  27.      zu- und abschalten zu können.
  28.  
  29. /* Hybris.c */
  30.  
  31. /* Stellen, die bei Integration von 6ern und 7ern geändert werden müssen,
  32.    sind (soweit erkannt) mit folgendem Kommentar versehen: */
  33.  
  34. /*67*/
  35.  
  36. /* nur 2.0-fähig ! */
  37.  
  38. #define MINROWS 4
  39. #define MAXROWS 35
  40. #define MINCOLS 3
  41. #define MAXCOLS 30
  42. #define MAXPARTS 7      /* ein Stein hat max. MAXPARTS 'Felder' */
  43. #define STEINE 28       /* Anzahl verschiedener Steine */
  44. #define MAXSTRESS 20    /* so stark können die einzelnen Gruppen maximal
  45.                            bewertet werden */
  46. #define BLOCKWIDTH 12   /* für die Grafik-Dimensionen */
  47. #define BLOCKHEIGHT 6
  48. #define MOVEDELAY 8     /* nach jedem Zug wird um MOVEDELAY/50s pausiert, um
  49.                            die Wiederholung zu verzögern */
  50.  
  51. #include <exec/types.h>
  52. #include <exec/memory.h>
  53. #include <exec/devices.h>
  54. #include <devices/gameport.h>
  55. #include <devices/inputevent.h>
  56. #include <libraries/dos.h>
  57. #include <libraries/gadtools.h>
  58. #include <intuition/intuition.h>
  59. /* Pseudo-IntuiMessage-Class für Joystick-Bewegungen: */
  60. #define IDCMP_JOY 0x01000000L
  61. #include <intuition/gadgetclass.h>
  62. #include <graphics/rastport.h>
  63. #include <utility/tagitem.h>
  64. #include <clib/exec_protos.h>
  65. #include <clib/dos_protos.h>
  66. #include <clib/intuition_protos.h>
  67. #include <clib/gadtools_protos.h>
  68. #include <clib/graphics_protos.h>
  69. #include <clib/alib_protos.h>
  70. #include <stdio.h>
  71.  
  72. /* Struktur, die einen (fallenden) Stein enthalten soll:
  73.    Teile enthält die Anzahl der NICHT-ZENTRALEN Teile; (0,0) = links oben
  74.    Breite enthält die Breite des Steines so, wie er beschrieben ist (und
  75.    eingeworfen wird). Diese Breite dient mit der u.a. Konvention über
  76.    MitteX zum positionieren der Steine im Zwei-Spieler-Modus             */
  77.  
  78. struct Stein { BYTE Teile,MitteX,MitteY,Breite;
  79.                BYTE OffsetX[MAXPARTS-1],OffsetY[MAXPARTS-1]; };
  80.  
  81. /* die Steine:
  82.     - für MitteY ist die Startposition beim Fallenlassen eingetragen
  83.     - für MitteX wird die Startposition beim Fallenlassen eingetragen
  84.     Als zentraler Stein ist zu wählen:
  85.     - bei geradzahliger Breite der Stein direkt links neben der Mitte
  86.     - bei ungeradzahliger Breite der Stein in der Mitte
  87.     (wird diese Regel durchbrochen, so kann bei länglichen Steinen nicht
  88.      garantiert werden, daß sie beim Auftauchen überhaupt ins Spielfeld
  89.      passen. Das wird aber erst akut, wenn der Stein zu einer Seite hin
  90.      weiter hinausragt, als der "gerade" Stein mit <Breite> Elementen.)  */
  91.  
  92. struct Stein Steine[STEINE]={
  93.     /*  0: #+## */  { 3,0,0,4, {-1,1,2,0,0,0},   {0,0,0,0,0,0} },
  94.  
  95.     /*  1: #+#
  96.              #  */  { 3,0,0,3, {-1,1,1,0,0,0},   {0,0,1,0,0,0} },
  97.  
  98.     /*  2: #+#
  99.             #   */  { 3,0,0,3, {-1,0,1,0,0,0},   {0,1,0,0,0,0} },
  100.  
  101.     /*  3: #+#
  102.            #    */  { 3,0,0,3, {-1,-1,1,0,0,0},  {0,1,0,0,0,0} },
  103.  
  104.     /*  4: #+
  105.             ##  */  { 3,0,0,3, {-1,0,1,0,0,0},   {0,1,1,0,0,0} },
  106.  
  107.     /*  5:  +#
  108.            ##   */  { 3,0,0,3, {-1,0,1,0,0,0},   {1,1,0,0,0,0} },
  109.  
  110.     /*  6: +#
  111.            ##   */  { 3,0,0,3, {0,1,1,0,0,0},    {1,0,1,0,0,0} },
  112.  
  113.     /*  7: +    */  { 0,0,0,1, {0,0,0,0,0,0},    {0,0,0,0,0,0} },
  114.  
  115.     /*  8: +#   */  { 1,0,0,2, {1,0,0,0,0,0},    {0,0,0,0,0,0} },
  116.  
  117.     /*  9: #+#  */  { 2,0,0,3, {-1,1,0,0,0,0},   {0,0,0,0,0,0} },
  118.  
  119.     /* 10: +#
  120.            #    */  { 2,0,0,2, {1,0,0,0,0,0},    {0,1,0,0,0,0} },
  121.  
  122.     /* 11: ##+## */ { 4,0,0,5, {-2,-1,1,2,0,0},  {0,0,0,0,0,0} },
  123.  
  124.     /* 12: ##+#
  125.               # */  { 4,0,0,5, {-2,-1,1,1,0,0},  {0,0,0,1,0,0} },
  126.  
  127.     /* 13: ##+#
  128.              #  */  { 4,0,0,5, {-2,-1,1,0,0,0},  {0,0,0,1,0,0} },
  129.  
  130.     /* 14: #+##
  131.             #   */  { 4,0,0,4, {-1,1,2,0,0,0},   {0,0,0,1,0,0} },
  132.  
  133.     /* 15: #+##
  134.            #    */  { 4,0,0,4, {-1,1,2,-1,0,0},  {0,0,0,1,0,0} },
  135.  
  136.     /* 16: ##+
  137.              ## */  { 4,0,0,5, {-2,-1,0,1,0,0},  {0,0,1,1,0,0} },
  138.  
  139.     /* 17: #+#
  140.             ##  */  { 4,0,0,3, {-1,1,0,1,0,0},   {0,0,1,1,0,0} },
  141.  
  142.     /* 18: #+#
  143.            # #  */  { 4,0,0,3, {-1,1,-1,1,0,0},  {0,0,1,1,0,0} },
  144.  
  145.     /* 19: #+#
  146.            ##   */  { 4,0,0,3, {-1,1,-1,0,0,0},  {0,0,1,1,0,0} },
  147.  
  148.     /* 20:  #+#
  149.            ##   */  { 4,0,0,5, {-1,1,-2,-1,0,0}, {0,0,1,1,0,0} },
  150.  
  151.     /* 21:  #+#
  152.             #
  153.             #   */  { 4,0,0,3, {-1,1,-1,-1,0,0}, {0,0,1,2,0,0} },
  154.  
  155.     /* 22: ###
  156.             +
  157.             #   */  { 4,0,1,3, {-1,0,1,0,0,0},   {-1,-1,-1,1,0,0} },
  158.  
  159.     /* 23:  #
  160.            #+#
  161.              #  */  { 4,0,1,3, {-1,0,1,1,0,0},   {0,-1,0,1,0,0} },
  162.  
  163.     /* 24: #
  164.            #+#
  165.              #  */  { 4,0,1,3, {-1,-1,1,1,0,0},  {0,-1,0,1,0,0} },
  166.  
  167.     /* 25:  #
  168.            #+#
  169.            #    */  { 4,0,1,3, {-1,0,1,-1,0,0},  {0,-1,0,1,0,0} },
  170.  
  171.     /* 26:   #
  172.            #+#
  173.            #    */  { 4,0,1,3, {-1,-1,1,1,0,0},  {0,1,0,-1,0,0} },
  174.  
  175.     /* 27:  #
  176.            #+#
  177.             #   */  { 4,0,1,3, {-1,0,0,1,0,0},   {0,-1,1,0,0,0} }
  178.     };
  179.  
  180. /* Zuordnung der verschiedenen Steinen zu Anzahl-Gruppen: */
  181. struct AGruppe { short von, bis; };
  182.  
  183. struct AGruppe Gruppen[8]= { {-1,0},  {7,7},   {8,8},   {9,10},
  184.                              {0,6},   {11,27}, {-1,0},  {-1,0}  };
  185.  
  186. /* Array mit den gegenwärtig erlaubten Stein-Nummern: */
  187. short                   erlaubte_steine[STEINE*MAXSTRESS],
  188.                         anzahl_erlaubter_steine;
  189.  
  190. /* Array mit den gegenwärtigen 'Betonungen' der Stein-Gruppen: */
  191. BYTE                    betonungen[8];
  192.  
  193. extern struct Library   *IntuitionBase; /* für Kickstart-Test */
  194. struct Library          *GadToolsBase=NULL;  /* damit unter 1.3 auch ein
  195.                                                 Fehler zustandekommt */
  196. struct Gadget           *GadgetList=NULL,*Gadgets[13];
  197. struct VisualInfo       *VInfo=NULL;
  198. struct Window           *window=NULL,*setupwindow=NULL,*pausewindow=NULL;
  199. struct RastPort         *RP;
  200. struct TextAttr         generalFont={(STRPTR)"topaz.font",TOPAZ_SIXTY,
  201.                                     FS_NORMAL,FPF_ROMFONT};
  202. struct TextFont         *genFont=NULL;
  203. struct IOStdReq         *game_io_msg=NULL;
  204. struct InputEvent       gamebuffer;
  205. struct MsgPort          *game_msg_port=NULL;
  206. BOOL                    gameport_open=FALSE,controller_type_set=FALSE,
  207.                         spiel_laeuft,zwei_spieler,collided[2],start,abort,
  208.                         preview;
  209. BYTE                    Spielfeld[MAXCOLS][MAXROWS],
  210.                         Steine_Pro_Zeile[MAXROWS],FallDelay,rows,cols;
  211. short                   abgesetzte_steine[2],abgesenkte_zeilen,y_zeilen,
  212.                         y_preview;
  213. struct Stein            aktueller_stein[2],naechster_stein[2];
  214.  
  215. static struct TagItem TAGA_DISABLE[]={ {GA_Disabled,TRUE}, {TAG_END,0} },
  216.                       TAGA_ENABLE[]={ {GA_Disabled,FALSE}, {TAG_END,0} };
  217.  
  218. int set_controller_type(short type)   /* aus joystick.c, Fish #5 */
  219. {
  220.     char tmp;
  221.  
  222.     game_io_msg->io_Command = GPD_SETCTYPE;
  223.                 /* set type of controller to mouse */
  224.     game_io_msg->io_Length = 1;
  225.     game_io_msg->io_Data = (APTR) &tmp;
  226.     tmp = type;
  227.  
  228.     DoIO(game_io_msg);
  229.     GetMsg(game_msg_port);
  230.     return((int)game_io_msg->io_Error);
  231. }
  232.  
  233. VOID ScratchMsgQueue(struct MsgPort *port)
  234. { /* alle anliegenden Messages beantworten */
  235.     struct Message *msg;
  236.  
  237.     while(msg=GetMsg(port)) ReplyMsg(msg);
  238. }
  239.  
  240. VOID error(char *str)
  241. {
  242.     BYTE AlertText[300];
  243.  
  244.     if(str)
  245.         {
  246.         AlertText[0]=0; AlertText[1]=100; AlertText[2]=20;
  247.         sprintf(&AlertText[3],"Hybris meldet Fehler: %s",str);
  248.         DisplayAlert(RECOVERY_ALERT,AlertText,38);
  249.         }
  250.     if(genFont)                 CloseFont(genFont);
  251.     if(window)
  252.         {
  253.         Forbid();
  254.         ScratchMsgQueue(window->UserPort);
  255.         CloseWindow(window);
  256.         Permit();
  257.         }
  258.     if(setupwindow)
  259.         {
  260.         Forbid();
  261.         ScratchMsgQueue(setupwindow->UserPort);
  262.         CloseWindow(setupwindow);
  263.         Permit();
  264.         }
  265.     if(pausewindow)
  266.         {
  267.         Forbid();
  268.         ScratchMsgQueue(pausewindow->UserPort);
  269.         CloseWindow(pausewindow);
  270.         Permit();
  271.         }
  272.     if(VInfo)                   FreeVisualInfo(VInfo);
  273.     if(controller_type_set)
  274.         {
  275.         if(!CheckIO(game_io_msg))       /* see if gameport read      */
  276.             AbortIO(game_io_msg);       /*   anything; Abort, if not */
  277.         WaitPort(game_msg_port);        /* wait for abort to complete */
  278.         GetMsg(game_msg_port);          /* and strip message from port */
  279.         set_controller_type(GPCT_NOCONTROLLER);
  280.         }
  281.     if(gameport_open)           CloseDevice(game_io_msg);
  282.     if(game_msg_port)           DeletePort(game_msg_port);
  283.     if(game_io_msg)             DeleteStdIO(game_io_msg);
  284.     if(GadToolsBase)
  285.         {
  286.         FreeGadgets(GadgetList);
  287.         CloseLibrary(GadToolsBase);
  288.         }
  289.     if(str)     exit(RETURN_ERROR);
  290.     else        exit(RETURN_OK);
  291. }
  292.  
  293. void Box1(WORD mode, WORD x0, WORD y0, WORD x1, WORD y1)
  294. {   /* 2.0-like Kasten außerhalb des angegebenen Rechtecks zeichnen */
  295.  
  296.     SetAPen(RP,mode ? 2 : 1);
  297.     Move(RP,x0-3,y1+2); Draw(RP,x1+3,y1+2); Draw(RP,x1+3,y0-2);
  298.     Move(RP,x1+2,y1+1); Draw(RP,x1+2,y0-1);
  299.     SetAPen(RP,mode ? 1 : 2);
  300.     Move(RP,x0-3,y1+2); Draw(RP,x0-3,y0-2); Draw(RP,x1+2,y0-2);
  301.     Move(RP,x0-2,y1+1); Draw(RP,x0-2,y0-1);
  302. }
  303.  
  304. void Box2(WORD mode, WORD x0, WORD y0, WORD x1, WORD y1)
  305. {   /* 2.0-like Kasten innerhalb des angegebenen Rechtecks zeichnen */
  306.  
  307.     SetAPen(RP,mode ? 2 : 1);
  308.     Move(RP,x0,y1);     Draw(RP,x1,y1);     Draw(RP,x1,y0);
  309.     Move(RP,x1-1,y1-1); Draw(RP,x1-1,y0+1);
  310.     SetAPen(RP,mode ? 1 : 2);
  311.     Move(RP,x0,y1);     Draw(RP,x0,y0);     Draw(RP,x1-1,y0);
  312.     Move(RP,x0+1,y1-1); Draw(RP,x0+1,y0+1);
  313. }
  314.  
  315. VOID ClearGamblingArea()
  316. {   /* Spielfeld grafisch löschen */
  317.     short x,y;
  318.  
  319. #define OX (BLOCKWIDTH/2-1)
  320. #define OY1 (BLOCKHEIGHT/2-2)
  321. #define OY2 (OY1+3)
  322.  
  323.     SetAPen(RP,0);
  324.     RectFill(RP,5,3,5+cols*BLOCKWIDTH,3+rows*BLOCKHEIGHT);
  325.     SetAPen(RP,1);
  326.     for(x=0;x<cols;++x)
  327.         for(y=0;y<rows;++y)
  328.             {
  329.             WritePixel(RP,5+OX+BLOCKWIDTH*x,3+OY1+BLOCKHEIGHT*y);
  330.             WritePixel(RP,5+OX+BLOCKWIDTH*x,3+OY2+BLOCKHEIGHT*y);
  331.             }
  332. }
  333.  
  334. VOID Print(char *text, SHORT xpos, SHORT ypos)
  335. {/* Ausgabe eines Textes */
  336.     Move(RP,xpos,ypos+RP->TxBaseline);
  337.     Text(RP,(UBYTE *)text,strlen(text));
  338. }
  339.  
  340. VOID Scoring()
  341. { /* Einblenden, wieviele Zeilen / Steine bereits gespielt */
  342.     char buffer[10];
  343.     static short old_s1=-1,old_s2=-1,old_z=-1;
  344.  
  345.     SetAPen(RP,1);
  346.     SetBPen(RP,0);
  347.     SetDrMd(RP,JAM2);
  348.     if(old_s1!=abgesetzte_steine[0])
  349.         {
  350.         sprintf(buffer,"%5d",old_s1=abgesetzte_steine[0]);
  351.         Print(buffer,16+cols*BLOCKWIDTH,7+RP->TxHeight);
  352.         }
  353.     if((old_s2!=abgesetzte_steine[1])&&zwei_spieler)
  354.         {
  355.         sprintf(buffer,"%5d",old_s2=abgesetzte_steine[1]);
  356.         Print(buffer,16+cols*BLOCKWIDTH,16+3*RP->TxHeight);
  357.         }
  358.     if(old_z!=abgesenkte_zeilen)
  359.         {
  360.         sprintf(buffer,"%5d",old_z=abgesenkte_zeilen);
  361.         Print(buffer,16+cols*BLOCKWIDTH,y_zeilen);
  362.         }
  363.     SetDrMd(RP,JAM1);
  364. }
  365.  
  366. struct Gadget *InitGads(struct VisualInfo *vi, struct NewWindow *nw)
  367. {
  368. #define NIL ((void *)0L)
  369.     static struct NewGadget GadgetArray[]={
  370.             {82,14,200,10,"Spalten",NIL,0,PLACETEXT_LEFT,NIL},
  371.             {82,2,200,10,"Zeilen ",NIL,1,PLACETEXT_LEFT,NIL},
  372.             {162,26,130,10,"Fallverzögerung",NIL,2,PLACETEXT_LEFT,NIL},
  373.             {102,38,92,12,"_# Spieler",NIL,3,PLACETEXT_LEFT,NIL},
  374.             {4,122,304,20,"Spiel _starten",NIL,4,PLACETEXT_IN,NIL}, /*67*/ /* {4,146,... */
  375.             {42,62,240,10,"1er",NIL,17,PLACETEXT_LEFT,NIL},
  376.             {42,74,240,10,"2er",NIL,18,PLACETEXT_LEFT,NIL},
  377.             {42,86,240,10,"3er",NIL,19,PLACETEXT_LEFT,NIL},
  378.             {42,98,240,10,"4er",NIL,20,PLACETEXT_LEFT,NIL},
  379.             {42,110,240,10,"5er",NIL,21,PLACETEXT_LEFT,NIL},
  380.             {42,122,240,10,"6er",NIL,22,PLACETEXT_LEFT,NIL},
  381.             {42,134,240,10,"7er",NIL,23,PLACETEXT_LEFT,NIL},
  382.             {282,38,12,12,"_Preview",NIL,5,PLACETEXT_LEFT,NIL}
  383.             };
  384.     static char *CycleArray_1[]={"1","2",(char *)NULL};
  385.     struct Gadget *gad;
  386.     struct NewGadget *ngad;
  387.     short i;
  388.     static struct TagItem TAGA_1[]={ {GTSL_Level,11},   {GTSL_Min,MINCOLS},
  389.                                      {GTSL_Max,MAXCOLS},
  390.                                      {GTSL_MaxLevelLen,3},
  391.                                      {GTSL_LevelFormat,(STRPTR)"%2ld"},
  392.                                      {GA_RelVerify,TRUE},
  393.                                      {GTSL_LevelPlace,PLACETEXT_RIGHT},
  394.                                      {TAG_END,0} },
  395.                           TAGA_2[]={ {GTSL_Min,1},   {GTSL_Max,9},
  396.                                      {GTSL_Level,0}, {GTSL_MaxLevelLen,2},
  397.                                      {GTSL_LevelFormat,(STRPTR)"%ld"},
  398.                                      {GA_RelVerify,TRUE},
  399.                                      {GTSL_LevelPlace,PLACETEXT_RIGHT},
  400.                                      {TAG_END,0} },
  401.                           TAGA_3[]={ {GTCY_Labels,CycleArray_1},
  402.                                      {GT_Underscore,'_'},    {TAG_END,0} };
  403.  
  404.     for(i=0,ngad=GadgetArray;i<sizeof(GadgetArray)/sizeof(struct NewGadget);
  405.             ++i,++ngad)
  406.         {
  407.         ngad->ng_VisualInfo=vi;
  408.         ngad->ng_TextAttr=&generalFont;
  409.         }
  410.     gad=CreateContext(&GadgetList);
  411.     if(gad==NULL)   return((struct Gadget *)NULL);
  412.     nw->FirstGadget=gad;
  413.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray,TAGA_1);
  414.     if(gad==NULL)   return((struct Gadget *)NULL);
  415.     Gadgets[0]=gad;
  416.     TAGA_1[0].ti_Data=20;
  417.     TAGA_1[1].ti_Data=MINROWS;
  418.     TAGA_1[2].ti_Data=MAXROWS;
  419.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+1,TAGA_1);
  420.     if(gad==NULL)   return((struct Gadget *)NULL);
  421.     Gadgets[1]=gad;
  422.     TAGA_2[2].ti_Data=FallDelay;
  423.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+2,TAGA_2);
  424.     if(gad==NULL)   return((struct Gadget *)NULL);
  425.     Gadgets[2]=gad;
  426.     gad=CreateGadgetA(CYCLE_KIND,gad,GadgetArray+3,TAGA_3);
  427.     if(gad==NULL)   return((struct Gadget *)NULL);
  428.     Gadgets[3]=gad;
  429.     gad=CreateGadgetA(BUTTON_KIND,gad,GadgetArray+4,TAGA_3+1);
  430.     if(gad==NULL)   return((struct Gadget *)NULL);
  431.     Gadgets[4]=gad;
  432.     TAGA_1[1].ti_Data=0;
  433.     TAGA_1[2].ti_Data=MAXSTRESS;
  434.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+5,TAGA_1+1);
  435.     if(gad==NULL)   return((struct Gadget *)NULL);
  436.     Gadgets[5]=gad;
  437.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+6,TAGA_1+1);
  438.     if(gad==NULL)   return((struct Gadget *)NULL);
  439.     Gadgets[6]=gad;
  440.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+7,TAGA_1+1);
  441.     if(gad==NULL)   return((struct Gadget *)NULL);
  442.     Gadgets[7]=gad;
  443.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+8,TAGA_1+1);
  444.     if(gad==NULL)   return((struct Gadget *)NULL);
  445.     Gadgets[8]=gad;
  446.     gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+9,TAGA_1+1);
  447.     if(gad==NULL)   return((struct Gadget *)NULL);
  448.     Gadgets[9]=gad;
  449.     /* TAGA_1[0].ti_Tag=GA_Disabled; */  /*67*/ /* entfällt / wird bei teilweiser Implementation relevant */
  450.     /* TAGA_1[0].ti_Data=TRUE; */        /*67*/ /* dto */
  451.     /*67*/ /* folgende Kommentarzeilen werden bei Implementation der 6er/7er gültig: */
  452.     /*67*/ /* gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+10,TAGA_1+1); */
  453.     /*67*/ /* if(gad==NULL)   return((struct Gadget *)NULL); */
  454.     /*67*/ /* Gadgets[10]=gad; */
  455.     /*67*/ /* gad=CreateGadgetA(SLIDER_KIND,gad,GadgetArray+11,TAGA_1+1); */
  456.     /*67*/ /* if(gad==NULL)   return((struct Gadget *)NULL); */
  457.     /*67*/ /* Gadgets[11]=gad; */
  458.     gad=CreateGadgetA(CHECKBOX_KIND,gad,GadgetArray+12,TAGA_3+1);
  459.     if(gad==NULL)   return((struct Gadget *)NULL);
  460.     Gadgets[12]=gad;
  461.     return(GadgetList);
  462. }
  463.  
  464. VOID ZeichneSteinchenRoh(BYTE farbe, short x, short y)
  465. { /* ein einzelnes Feld bei Grafik-Koordinaten x/y [linke obere Ecke]
  466.      zeichnen */
  467.   /* farbe: 0 - leer, 1 & 2: Kästchen, 1: blaues Kästchen */
  468.  
  469.     if(farbe)
  470.         {
  471.         Box2(FALSE,x,y,x+BLOCKWIDTH-1,y+BLOCKHEIGHT-1);
  472.         SetAPen(RP,(farbe==1) ? 3 : 0);
  473.         RectFill(RP,2+x,1+y,x+BLOCKWIDTH-3,y+BLOCKHEIGHT-2);
  474.         }
  475.     else{
  476.         SetAPen(RP,0);
  477.         RectFill(RP,x,y,x+BLOCKWIDTH-1,y+BLOCKHEIGHT-1);
  478.         SetAPen(RP,1);
  479.         WritePixel(RP,OX+x,OY1+y);
  480.         WritePixel(RP,OX+x,OY2+y);
  481.         }
  482. }
  483.  
  484. VOID ZeichneSteinchen(BYTE farbe, BYTE x, BYTE y)
  485. { /* ein einzelnes Feld bei Feld-Koordinaten x/y zeichnen */
  486.   /* farbe: 0 - leer, 1 & 2: Kästchen, 1: blaues Kästchen */
  487.  
  488.     ZeichneSteinchenRoh(farbe,5+x*BLOCKWIDTH,3+y*BLOCKHEIGHT);
  489. }
  490.  
  491. VOID ZeichneStein(struct Stein *stein, BYTE farbe)
  492. { /* kompletten Spielstein zeichnen */
  493.   /* farbe: 0 - leer, 1: blau, 2:grau */
  494.     BYTE cnt,x,y;
  495.  
  496.     ZeichneSteinchen(farbe,x=stein->MitteX,y=stein->MitteY);
  497.     for(cnt=0;cnt<stein->Teile;++cnt)
  498.         ZeichneSteinchen(farbe,x+stein->OffsetX[cnt],y+stein->OffsetY[cnt]);
  499. }
  500.  
  501. VOID Preview(BYTE spieler)
  502. { /* den naechsten_stein des angegebenen Spielers neu auslosen und ggf.
  503.      einblenden */
  504.     short x,y,cnt;
  505.     struct Stein *stein;
  506.  
  507.     if(anzahl_erlaubter_steine==0)  return;
  508.     stein=naechster_stein+spieler;
  509.     *stein=Steine[erlaubte_steine[
  510.                                 RangeRand(anzahl_erlaubter_steine) ] ];
  511.     /* Grafik-Koordinaten für Preview: */
  512.     x=16+cols*BLOCKWIDTH+RP->TxWidth*6-BLOCKWIDTH/2+
  513.         (stein->MitteX-(cols-1)/2)*BLOCKWIDTH;
  514.     /* Korrektur der Startposition bei Zwei-Spieler-Modus: */
  515.     if(zwei_spieler)
  516.         {
  517.         if(spieler)     stein->MitteX+=(stein->Breite+1)/2;
  518.         else            stein->MitteX-=stein->Breite/2+1;
  519.         }
  520.     if(!preview)        return;
  521.  
  522.     /* eigentliche Einblendung */
  523.     y=y_preview+spieler*((MAXPARTS+3)/2)*BLOCKHEIGHT;
  524.     SetAPen(RP,0);
  525.     RectFill(RP,x-((MAXPARTS-1)/2)*BLOCKWIDTH,  y,
  526.                 x+((MAXPARTS+1)/2)*BLOCKWIDTH-1,
  527.                 y+((MAXPARTS+1)/2)*BLOCKHEIGHT-1);
  528.     y+=stein->MitteY*BLOCKHEIGHT;
  529.     ZeichneSteinchenRoh(spieler+1,x,y);
  530.     for(cnt=0;cnt<stein->Teile;++cnt)
  531.         ZeichneSteinchenRoh(spieler+1,x+stein->OffsetX[cnt]*BLOCKWIDTH,
  532.                                       y+stein->OffsetY[cnt]*BLOCKHEIGHT);
  533. }
  534.  
  535. VOID init_window()
  536. { /* die grafischen Elemente des Windows (neu) aufbauen */
  537.     short cnt;
  538.  
  539.     SetRast(RP,0);
  540.     SetDrMd(RP,JAM1);
  541.     Box1(TRUE,5,3,4+cols*BLOCKWIDTH,2+rows*BLOCKHEIGHT);
  542.     Box1(FALSE,14+cols*BLOCKWIDTH,3,
  543.                15+cols*BLOCKWIDTH+12*RP->TxWidth,2+2*(RP->TxHeight+2));
  544.     if(zwei_spieler)
  545.         {
  546.         Box1(FALSE,14+cols*BLOCKWIDTH,8+2*(RP->TxHeight+2),
  547.                    15+cols*BLOCKWIDTH+12*RP->TxWidth,7+4*(RP->TxHeight+2));
  548.         }
  549.     y_zeilen=8+(2+3*zwei_spieler)*RP->TxHeight;
  550.     Box1(FALSE,14+cols*BLOCKWIDTH,y_zeilen+4,
  551.                15+cols*BLOCKWIDTH+12*RP->TxWidth,y_zeilen+5+RP->TxHeight);
  552.     y_preview=y_zeilen+RP->TxHeight+7;
  553.     if(preview)
  554.         Box1(FALSE,14+cols*BLOCKWIDTH,y_preview+4,
  555.                    15+cols*BLOCKWIDTH+12*RP->TxWidth,
  556.                    y_preview+9+RP->TxHeight+(4+5*zwei_spieler)*BLOCKHEIGHT);
  557.     SetAPen(RP,1);
  558.     Print("Spieler 1:",16+cols*BLOCKWIDTH+RP->TxWidth,5);
  559.     Print("Steine",16+cols*BLOCKWIDTH+6*RP->TxWidth,7+RP->TxHeight);
  560.     if(zwei_spieler)
  561.         {
  562.         Print("Spieler 2:",16+cols*BLOCKWIDTH+RP->TxWidth,14+2*RP->TxHeight);
  563.         Print("Steine",16+cols*BLOCKWIDTH+6*RP->TxWidth,16+3*RP->TxHeight);
  564.         }
  565.     y_zeilen+=RP->TxBaseline;
  566.     Print("Zeilen",16+cols*BLOCKWIDTH+6*RP->TxWidth,y_zeilen);
  567.     if(preview)
  568.         {
  569.         Print(zwei_spieler ? "Nächste:" : "Nächster:",
  570.               16+cols*BLOCKWIDTH+RP->TxWidth/2+((1+zwei_spieler)*RP->TxWidth)/2,
  571.               y_preview+RP->TxBaseline);
  572.         y_preview+=RP->TxHeight+8;
  573.         Preview(0);
  574.         if(zwei_spieler)    Preview(1);
  575.         }
  576.     ClearGamblingArea();
  577. }
  578.  
  579. VOID ResizeWindow();
  580.  
  581. VOID init()
  582. {
  583. #define IDCMP_KEYS IDCMP_VANILLAKEY|IDCMP_RAWKEY
  584. #define STD_WFLGS WFLG_GIMMEZEROZERO|WFLG_RMBTRAP|WFLG_DRAGBAR|WFLG_DEPTHGADGET
  585.     static struct NewWindow pwin={5,12,0,0,-1,-1,
  586.                                 IDCMP_KEYS|IDCMP_CHANGEWINDOW|IDCMP_INTUITICKS,
  587.                                 STD_WFLGS|WFLG_SMART_REFRESH,
  588.                                 NULL,NULL,(UBYTE *)"Hybris V1.3 - Game",
  589.                                 NULL,NULL,5,5,640,256,WBENCHSCREEN},
  590.                             swin={310,12,320,157,-1,-1, /*67*/ /* ...,320,181,-1,... */
  591.                                 IDCMP_KEYS|SLIDERIDCMP|BUTTONIDCMP|IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW,
  592.                                 STD_WFLGS|WFLG_SIMPLE_REFRESH|WFLG_CLOSEGADGET,
  593.                                 NULL,NULL,(UBYTE *)"Hybris V1.3 - Setup",
  594.                                 NULL,NULL,5,5,640,256,WBENCHSCREEN};
  595.  
  596.     struct GamePortTrigger gpt;
  597.     extern ULONG RangeSeed;
  598.     struct Screen *wbscreen;
  599.     short cnt;
  600.  
  601.     if(IntuitionBase->lib_Version<36) error("Kickstart 2.0 erforderlich");
  602.     CurrentTime(&RangeSeed,&RangeSeed);
  603.     if(!(GadToolsBase=OpenLibrary("gadtools.library",36)))
  604.         error("gadtools.library V36+ erforderlich");
  605.  
  606.     /* Vorbereitung der GamePort-Abfrage */
  607.     if(!(game_msg_port=CreatePort(NULL,0)))
  608.         error("CreatePort() fehlgeschlagen");
  609.     if(!(game_io_msg=CreateStdIO(game_msg_port)))
  610.         error("CreateStdIO() fehlgeschlagen");
  611.     if(OpenDevice("gameport.device",1,game_io_msg,0))
  612.         error("gameport.device läßt sich nicht öffnen");
  613.     gameport_open=TRUE;
  614.     if(set_controller_type(GPCT_ABSJOYSTICK))   /* Abfragemodus bestimmen */
  615.         error("Probleme mit GPCT_ABSJOYSTICK");
  616.     controller_type_set=TRUE;
  617.     game_io_msg->io_Command=GPD_SETTRIGGER;     /* Abfragemodus, 2. Teil ? */
  618.     game_io_msg->io_Length=sizeof(gpt);
  619.     game_io_msg->io_Data=(APTR)&gpt;
  620.     gpt.gpt_Keys=GPTF_UPKEYS+GPTF_DOWNKEYS;
  621.     gpt.gpt_Timeout=MOVEDELAY;
  622.     gpt.gpt_XDelta=gpt.gpt_YDelta=1;
  623.     if(DoIO(game_io_msg))       error("Probleme mit GPD_SETTRIGGER");
  624.     game_io_msg->io_Command = GPD_READEVENT;    /* ab jetzt nur noch abfragen */
  625.     game_io_msg->io_Data = (APTR)&gamebuffer;
  626.         /* into the input buffer, one at a time. */
  627.         /* read-event waits for the preset conditions */
  628.     game_io_msg->io_Length = sizeof(struct InputEvent);
  629.         /* read one event each time we go back to the gameport */
  630.     game_io_msg->io_Flags = 0;  /* dont use quick io */
  631.     game_io_msg->io_Length = sizeof(struct InputEvent);
  632.         /* jeweils EIN Event lesen */
  633.     SendIO(game_io_msg);        /* Anfrage starten */
  634.  
  635.     /* Aufbau des Setup-Windows */
  636.     if(!(wbscreen=LockPubScreen(NULL))) error("Kein PubScreen verfügbar !");
  637.     if(!(VInfo=GetVisualInfo(wbscreen,TAG_END)))
  638.         error("VisualInfo nicht verfügbar");
  639.     if(!(genFont=OpenFont(&generalFont)))
  640.         error("Font topaz/9 läßt sich nicht öffnen !");
  641.     if(!(InitGads(VInfo,&swin)))        error("Gadgets nicht verfügbar");
  642.     swin.Screen=wbscreen;
  643.     if(!(setupwindow=OpenWindowTags(&swin,WA_InnerWidth,(ULONG)312,
  644.                                     WA_InnerHeight,(ULONG)144,TAG_END)))
  645.         error("Setup-Window läßt sich nicht öffnen");
  646.     SetFont(setupwindow->RPort,genFont);
  647.     GT_RefreshWindow(setupwindow,NULL);
  648.  
  649.     /* Aufbau des Spiel-Windows */
  650.     pwin.Width=21+cols*BLOCKWIDTH+12*genFont->tf_XSize;
  651.     pwin.Height=6+rows*BLOCKHEIGHT;
  652.     pwin.Screen=wbscreen;
  653.     if(!(window=OpenWindowTags(&pwin,WA_InnerWidth,(ULONG)pwin.Width,
  654.                                WA_InnerHeight,(ULONG)pwin.Height)))
  655.         error("Spiel-Window läßt sich nicht öffnen");
  656.     UnlockPubScreen(NULL,wbscreen);
  657.     RP=window->RPort;
  658.     SetFont(RP,genFont);
  659.     /* Spiel-Window aufbauen */
  660.     ResizeWindow();
  661. }
  662.  
  663. VOID wechsle_betonung(BYTE nr, BYTE betonung)
  664. { /* wechselt für die (nr)er-Steine des Erlaubtheits-Status und setzt dem-
  665.      entsprechend Spielsart als erlaubt / verboten. Das Gadget selbst wird
  666.      nicht aktualisiert */
  667.  
  668.     short cnt1,cnt2,cnt3;
  669.  
  670.     /* geht das überhaupt ? */
  671.     if(betonung>0)  /* Betonung 0 geht immer */
  672.         if((nr+(1+nr)*zwei_spieler)>cols)
  673.             return; /* geht nicht */
  674.     /* Abzählen, wieviele Stein-Gruppen noch erlaubt sind: */
  675.     for(cnt1=1,cnt3=0;cnt1<8;++cnt1)
  676.         cnt3+=(betonungen[cnt1]>0);
  677.     /* wenn 1. das Spiel läuft und 2. die letzte erlaubte Gruppe gesperrt
  678.        werden soll: Gadget-Anwahl zurücknehmen und keine weitere Aktion */
  679.     if(spiel_laeuft && (cnt3==1) && (betonungen[nr]>0) && (betonung==0) )
  680.         {
  681.         GT_SetGadgetAttrs(Gadgets[nr+4],setupwindow,NULL,
  682.                           GTSL_Level,betonungen[nr],TAG_END);
  683.         return;
  684.         }
  685.     betonungen[nr]=betonung;
  686.     GT_SetGadgetAttrs(Gadgets[nr+4],setupwindow,NULL,GTSL_Level,betonung,
  687.                       TAG_END);
  688.     /* Liste aller erlaubten Steine vorbereiten: */
  689.     anzahl_erlaubter_steine=0;
  690.     for(cnt1=1;cnt1<8;++cnt1)
  691.         for(cnt2=0;cnt2<betonungen[cnt1];++cnt2)
  692.             if(Gruppen[cnt1].von>=0)
  693.                 /* Steine mit <cnt1> Elementen einreihen */
  694.                 for(cnt3=Gruppen[cnt1].von;cnt3<=Gruppen[cnt1].bis;++cnt3)
  695.                     erlaubte_steine[anzahl_erlaubter_steine++]=cnt3;
  696.     if(!spiel_laeuft)
  697.         GT_SetGadgetAttrs(Gadgets[4],setupwindow,NULL,GA_Disabled,
  698.                           anzahl_erlaubter_steine==0,TAG_END);
  699.     /* neue Steine neu auslosen */
  700.     Preview(0);
  701.     if(zwei_spieler)    Preview(1);
  702. }
  703.  
  704. struct IntuiMessage *WaitMessage();
  705.  
  706. VOID ResizeWindow()
  707. { /* Die Spiel-Window-Größe den aktuellen Bedürfnissen (Zeilen, Spalten,
  708.     Spielerzahl, Preview) anpassen */
  709.  
  710.     short width,height1,height2;
  711.  
  712.     width=21+cols*BLOCKWIDTH+12*genFont->tf_XSize;
  713.     height1=6+rows*BLOCKHEIGHT;
  714.     height2=26+genFont->tf_YSize*(2+3*zwei_spieler)+
  715.             (11+RP->TxHeight+
  716.              ((MAXPARTS+1)/2*(1+zwei_spieler)+zwei_spieler)*BLOCKHEIGHT) *
  717.             preview;
  718.     if(height2>height1) height1=height2;
  719.     if((window->Width!=width)||(window->Height!=height1));
  720.         {
  721.         ChangeWindowBox(window,window->LeftEdge,window->TopEdge,
  722.                         width+window->BorderRight+window->BorderLeft,
  723.                         height1+window->BorderTop+window->BorderBottom);
  724.         while(WaitMessage()->Class!=IDCMP_CHANGEWINDOW);
  725.         }
  726.     /* die Start-X-Positionen dem gegebenen Spielfeld anpassen */
  727.     for(width=0;width<STEINE;++width) Steine[width].MitteX=(cols-1)/2;
  728.     init_window();
  729.  
  730.     /* die einzelnen Spielstein-Gruppen gemäß Spielfeldbreite
  731.        (erlauben) / (verbieten und mit 0 'betonen')             */
  732.     for(width=2;width<=MAXPARTS-2;++width)  /*67*/ /*width<=MAXPARTS*/
  733.         {
  734.         if((width+(1+width)*zwei_spieler)>cols)
  735.             { /* geht nicht */
  736.             wechsle_betonung(width,0);
  737.             GT_SetGadgetAttrs(Gadgets[width+4],setupwindow,NULL,
  738.                               GTSL_Level,0,GA_Disabled,TRUE,TAG_END);
  739.             }
  740.         else /* geht */
  741.             GT_SetGadgetAttrsA(Gadgets[width+4],setupwindow,NULL,TAGA_ENABLE);
  742.         }
  743. }
  744.  
  745. VOID Inc_FallDelay()
  746. { /* erhöht (wenn möglich) die Fallverzögerung um eins */
  747.     if(FallDelay==9)    return;
  748.     GT_SetGadgetAttrs(Gadgets[2],setupwindow,NULL,GTSL_Level,++FallDelay,
  749.                       TAG_END);
  750. }
  751.  
  752. VOID Dec_FallDelay()
  753. { /* erniedrigt (wenn möglich) die Fallverzögerung um eins */
  754.     if(FallDelay==1)    return;
  755.     GT_SetGadgetAttrs(Gadgets[2],setupwindow,NULL,GTSL_Level,--FallDelay,
  756.                       TAG_END);
  757. }
  758.  
  759. VOID Inc_Spalten()
  760. { /* erhöht (wenn möglich) die Spaltenzahl um eins */
  761.     if(cols==MAXCOLS)   return;
  762.     GT_SetGadgetAttrs(Gadgets[0],setupwindow,NULL,GTSL_Level,++cols,
  763.                       TAG_END);
  764.     ResizeWindow();
  765. }
  766.  
  767. VOID Dec_Spalten()
  768. { /* erniedrigt (wenn möglich) die Spaltenzahl um eins */
  769.     if(cols==MINCOLS)   return;
  770.     GT_SetGadgetAttrs(Gadgets[0],setupwindow,NULL,GTSL_Level,--cols,
  771.                       TAG_END);
  772.     ResizeWindow();
  773. }
  774.  
  775. VOID Inc_Zeilen()
  776. { /* erhöht (wenn möglich) die Zeilenzahl um eins */
  777.     if(rows==MAXROWS)   return;
  778.     GT_SetGadgetAttrs(Gadgets[1],setupwindow,NULL,GTSL_Level,++rows,
  779.                       TAG_END);
  780.     ResizeWindow();
  781. }
  782.  
  783. VOID Dec_Zeilen()
  784. { /* erniedrigt (wenn möglich) die Zeilenzahl um eins */
  785.     if(rows==MINROWS)   return;
  786.     GT_SetGadgetAttrs(Gadgets[1],setupwindow,NULL,GTSL_Level,--rows,
  787.                       TAG_END);
  788.     ResizeWindow();
  789. }
  790.  
  791. struct IntuiMessage *GetMessage(struct Window *wd)
  792. {/* MsgPort des angegebenen Windows auslesen; liefert die Adresse einer
  793.     Kopie der gelesenen Message bzw. NULL, falls keine Message anliegt
  794.     - IDCMP_RAWKEY:
  795.         - Code == eine der F-Tasten:
  796.             Steuerung der Betonungs-Gadgets und NULL-Ergebnis.
  797.         - wd == setupwindow && !spiel_laeuft:
  798.             - Qualifier==0 :
  799.                 - CursorUp: Zeilenzahl decrementieren
  800.                 - CursorDown: Zeilenzahl incrementieren
  801.                 - CursorRight: Spaltenzahl incrementieren
  802.                 - CursorLeft: Spaltenzahl decrementieren
  803.             - Qualifier & SHIFT :
  804.                 - CursorUp, CursorRight: Fallverzögerung incrementieren
  805.                 - CursorDown, CursorLeft: Fallverzögerung decrementieren
  806.             wenn eines davon: NULL-Ergebnis.
  807.     - bei IDCMP_VANILLAKEY und Code==27 (ESC):
  808.         - IDCMPWindow == setupwindow : siehe IDCMP_CLOSEWINDOW
  809.         - IDCMPWindow == window und spiel_laeuft : Kontrollnachfrage
  810.             (Spielabbruch). Bei Bestätigung wird abort gesetzt.
  811.             NULL-Ergebnis.
  812.     - bei IDCMP_VANILLAKEY und IDCMPWindow==setupwindow:
  813.         - '1'-'5': Stein-Gruppen 1-5 erlaubt und NULL-Ergebnis
  814.         - 's', 'S': Start=anzahl_erlaubter_steine>0 && !spiel_laeuft;
  815.         - '#': Spielerzahl wechseln 1 <-> 2
  816.         - 'p', 'P': Preview negieren (nicht während des Spiels !)
  817.     - bei IDCMP_CLOSEWINDOW: gesicherter Ausstieg, bei Ablehnung:
  818.       NULL-Ergebnis
  819.     - bei IDCMP_REFRESHWINDOW : GT_BeginRefresh() ; GT_EndRefresh();
  820.       NULL-Ergebnis
  821.     - bei Gadget-Anwahl: Einstellung des jeweiligen Parameters:
  822.         - Gadget 0: Spalten
  823.         - Gadget 1: Zeilen
  824.         - Gadget 2: Fallverzögerung
  825.         - Gadget 3: Spielerzahl
  826.         - Gadget 4: Spielstart
  827.         - Gadgets 17-23: Stein-Gruppen 1-7 erlaubt
  828.         - Gadget 5: Preview
  829.       und korrektes, aber eben schon ausgewertetes Ergebnis             */
  830.  
  831.     static struct IntuiMessage gotten;
  832.     struct IntuiMessage *msg;
  833.     static UBYTE del=10;
  834.     static struct IntuiText
  835.         oktext={2,1,JAM1,6,4,&generalFont,(UBYTE *)"Ja",NULL},
  836.         notext={2,1,JAM1,6,4,&generalFont,(UBYTE *)"Nein",NULL},
  837.         text2={2,1,JAM1,9,13,&generalFont,NULL,NULL},
  838.         text1={2,1,JAM1,9,4,&generalFont,NULL,&text2};
  839.     short y,code;
  840.     USHORT qual;
  841.  
  842.     if(!(msg=GT_GetIMsg(wd->UserPort))) return(NULL);
  843.     gotten=*msg;    wd=gotten.IDCMPWindow;
  844.     GT_ReplyIMsg(msg);
  845.     if((gotten.Class==IDCMP_VANILLAKEY)&&(gotten.Code==27))
  846.         {
  847.         if(wd==setupwindow)
  848.             gotten.Class=IDCMP_CLOSEWINDOW; /* ESC wird als Abbruch verstanden */
  849.         else if((wd==window)&& spiel_laeuft)
  850.             {
  851.             text1.IText=(UBYTE *)"Wollen   Sie  das";
  852.             text2.IText=(UBYTE *)"Spiel abbrechen ?";
  853.             abort=AutoRequest(wd,&text1,&oktext,¬ext,NULL,NULL,210,58);
  854.             return(NULL);
  855.             }
  856.         }
  857.     if((gotten.Class==IDCMP_CLOSEWINDOW)&&(wd==setupwindow))
  858.             {
  859.         text1.IText=(UBYTE *)"Wollen    Sie    das";
  860.         text2.IText=(UBYTE *)"Programm verlassen ?";
  861.         if(AutoRequest(wd,&text1,&oktext,¬ext,NULL,NULL,237,58))
  862.             error(NULL);
  863.         return(NULL);
  864.         }
  865.     else if(gotten.Class==IDCMP_INTUITICKS)
  866.         {
  867.         /* schlucken ? */
  868.         if(!spiel_laeuft)   return(NULL);
  869.         if(--del)           return(NULL);
  870.         del=FallDelay;
  871.         }
  872.     else if(gotten.Class==IDCMP_REFRESHWINDOW)
  873.         {
  874.         GT_BeginRefresh(wd);
  875.         SetAPen(wd->RPort,1);
  876.         SetDrMd(wd->RPort,JAM1);
  877.         Move(wd->RPort,126,58);
  878.         Text(wd->RPort,"Steine:",7);
  879.         GT_EndRefresh(wd,TRUE);
  880.         return(NULL);
  881.         }
  882.     else if(gotten.Class==IDCMP_GADGETUP)
  883.         { short gadgetid=((struct Gadget *)msg->IAddress)->GadgetID;
  884.         switch(gadgetid)
  885.             {
  886.             case 0:  if(cols!=msg->Code)
  887.                         {
  888.                         cols=msg->Code;
  889.                         ResizeWindow();
  890.                         }
  891.                      break;
  892.             case 1:  if(rows!=msg->Code)
  893.                         {
  894.                         rows=msg->Code;
  895.                         ResizeWindow();
  896.                         }
  897.                      break;
  898.             case 2:  FallDelay=msg->Code;       break;
  899.             case 3:  zwei_spieler=msg->Code;
  900.                      ResizeWindow();
  901.                      break;
  902.             case 4:  start=TRUE;    break;
  903.             case 5:  preview=!preview;
  904.                      ResizeWindow();
  905.                      GT_SetGadgetAttrs(Gadgets[12],setupwindow,NULL,
  906.                                        GTCB_Checked,preview,TAG_END);
  907.                      break;
  908.             case 17:
  909.             case 18:
  910.             case 19:
  911.             case 20:
  912.             case 21:
  913.             case 22:
  914.             case 23: wechsle_betonung(gadgetid-16,msg->Code);   break;
  915.             }
  916.         if(spiel_laeuft)   ActivateWindow(window);
  917.         }
  918.     else if( (gotten.Class==IDCMP_VANILLAKEY) && (wd==setupwindow) &&
  919.              !spiel_laeuft )
  920.         { /* alle Setup-Window-VANILLAKEY-Kommandos sind im Spiel tot */
  921.         switch(msg->Code)
  922.             {
  923.             case 's':
  924.             case 'S':   start=anzahl_erlaubter_steine>0;    break;
  925.             case 'p':
  926.             case 'P':   preview=!preview;
  927.                         ResizeWindow();
  928.                         GT_SetGadgetAttrs(Gadgets[12],setupwindow,NULL,
  929.                                           GTCB_Checked,preview,TAG_END);
  930.                         break;
  931.             case '#':   zwei_spieler=!zwei_spieler;
  932.                         ResizeWindow();
  933.                         GT_SetGadgetAttrs(Gadgets[3],setupwindow,NULL,
  934.                                           GTCY_Active,zwei_spieler,TAG_END);
  935.                         break;
  936.             }
  937.         }
  938.     else if(gotten.Class==IDCMP_RAWKEY)
  939.         {
  940.         code=msg->Code;
  941.         if((code>0x4f)&&(code<0x55)) /*67*/ /* 2. Bed.: code<0x57 */
  942.             {
  943.             code-=0x4f;
  944.             qual=msg->Qualifier & ~(IEQUALIFIER_RELATIVEMOUSE |
  945.                                     IEQUALIFIER_REPEAT |
  946.                                     IEQUALIFIER_MIDBUTTON |
  947.                                     IEQUALIFIER_RBUTTON |
  948.                                     IEQUALIFIER_LEFTBUTTON)     ;
  949.             switch(qual)
  950.                 {
  951.                 case 0:
  952.                     if(betonungen[code]<MAXSTRESS)
  953.                         wechsle_betonung(code,betonungen[code]+1);
  954.                     break;
  955.                 case IEQUALIFIER_LSHIFT:
  956.                 case IEQUALIFIER_RSHIFT:
  957.                     if(betonungen[code]>0)
  958.                         wechsle_betonung(code,betonungen[code]-1);
  959.                     break;
  960.                 case IEQUALIFIER_CONTROL:
  961.                     wechsle_betonung(code,0);           break;
  962.                 case IEQUALIFIER_LALT:
  963.                 case IEQUALIFIER_RALT:
  964.                     wechsle_betonung(code,1);           break;
  965.                 case IEQUALIFIER_LCOMMAND:
  966.                 case IEQUALIFIER_RCOMMAND:
  967.                     wechsle_betonung(code,MAXSTRESS);   break;
  968.                 }
  969.             return(NULL);
  970.             }
  971.         else if((wd==setupwindow) && !spiel_laeuft)
  972.             { /* Steuerung der Gadgets Zeilen, Spalten, Fallverzögerung ? */
  973.             qual=msg->Qualifier & ~(IEQUALIFIER_RELATIVEMOUSE |
  974.                                     IEQUALIFIER_REPEAT |
  975.                                     IEQUALIFIER_MIDBUTTON |
  976.                                     IEQUALIFIER_RBUTTON |
  977.                                     IEQUALIFIER_LEFTBUTTON)     ;
  978.             if(qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT) )
  979.                 { /* mit Shift: Fallverzögerung */
  980.                 switch(code)
  981.                     {
  982.                     case 0x4d:
  983.                     case 0x4f:  Dec_FallDelay();    break;
  984.                     case 0x4c:
  985.                     case 0x4e:  Inc_FallDelay();    break;
  986.                     }
  987.                 }
  988.             else{ /* ohne Shift: Zeilen / Spalten */
  989.                 switch(code)
  990.                     {
  991.                     case 0x4d:  Inc_Zeilen();   break;
  992.                     case 0x4f:  Dec_Spalten();  break;
  993.                     case 0x4c:  Dec_Zeilen();   break;
  994.                     case 0x4e:  Inc_Spalten();  break;
  995.                     }
  996.                 }
  997.             }
  998.         }
  999.     return(&gotten);
  1000. }
  1001.  
  1002. struct IntuiMessage *GetJoy()
  1003. { /* liest den Joystick aus und ergibt im Spiel einen Zeiger auf ein Pseudo-
  1004.      IntuiMessage, wenn der Joystick NICHT im Ruhezustand ist.
  1005. /*     Falls !spiel_laeuft, wird NULL zurückgegeben, nachdem ggf. folgende
  1006. /*     Veränderungen vorgenommen wurden:
  1007. /*     - Feuer nicht gedrückt:
  1008. /*        - Up: Zeilenzahl incrementieren
  1009. /*        - Down: Zeilenzahl decrementieren
  1010. /*        - Right: Spaltenzahl incrementieren
  1011. /*        - Left: Spaltenzahl decrementieren
  1012. /*     - Feuer gedrückt:
  1013. /*        - Up, Right: Fallverzögerung incrementieren
  1014. /*        - Down, Left: Fallverzögerung decrementieren                      */
  1015.  
  1016.     static struct IntuiMessage joy_message={{0},IDCMP_JOY,0,FALSE,
  1017.                                             NULL,0,0,0,0,NULL,NULL};
  1018.     static UWORD oldqual=FALSE;
  1019.     UWORD help;
  1020.  
  1021.     if(GetMsg(game_msg_port))
  1022.         { /* Daten lesen */
  1023.         joy_message.MouseX=gamebuffer.ie_X;
  1024.         joy_message.MouseY=gamebuffer.ie_Y;
  1025.         if(gamebuffer.ie_Code==IECODE_LBUTTON)
  1026.             joy_message.Qualifier=TRUE;
  1027.         else if(gamebuffer.ie_Code==IECODE_LBUTTON+IECODE_UP_PREFIX)
  1028.             joy_message.Qualifier=FALSE;
  1029.         /* Abfrage neu starten */
  1030.         game_io_msg->io_Length = sizeof(struct InputEvent);
  1031.                 /* jeweils EIN Event lesen */
  1032.         SendIO(game_io_msg); /* los */
  1033.         /* wenn alles wie beim letzten Mal war UND der Feuer-Knopf
  1034.            nicht gedrückt : Message schlucken */
  1035.         help=oldqual;
  1036.         if((oldqual=joy_message.Qualifier) || help ||
  1037.            joy_message.MouseX || joy_message.MouseY)
  1038.             return(&joy_message);
  1039. /*            { /* ggf. Message dekodieren */
  1040. /*            if(spiel_laeuft)    return(&joy_message);
  1041. /*            if(joy_message.Qualifier)
  1042. /*                { /* Fallverzögerung */
  1043. /*                switch(joy_message.MouseX)
  1044. /*                    {
  1045. /*                    case -1:    Dec_FallDelay();    break;
  1046. /*                    case 1:     Inc_FallDelay();    break;
  1047. /*                    case 0:     switch(joy_message.MouseY)
  1048. /*                                    {
  1049. /*                                    case -1:    Inc_FallDelay();    break;
  1050. /*                                    case 1:     Dec_FallDelay();    break;
  1051. /*                                    }
  1052. /*                                break;
  1053. /*                    }
  1054. /*                }
  1055. /*            else{ /* Zeilen / Spalten */
  1056. /*                switch(joy_message.MouseX)
  1057. /*                    {
  1058. /*                    case -1:    Dec_Spalten();  break;
  1059. /*                    case 1:     Inc_Spalten();  break;
  1060. /*                    case 0:     switch(joy_message.MouseY)
  1061. /*                                    {
  1062. /*                                    case -1:    Inc_Zeilen();   break;
  1063. /*                                    case 1:     Dec_Zeilen();   break;
  1064. /*                                    }
  1065. /*                                break;
  1066. /*                    }
  1067. /*                }
  1068. /*            } */
  1069.         }
  1070.     return(NULL);
  1071. }
  1072.  
  1073. struct IntuiMessage *WaitMessage()
  1074. {/* ggf. auf eine Message warten, diese lesen; liefert die Adresse einer Kopie
  1075.     der gelesenen Message.      */
  1076.     struct IntuiMessage *msg;
  1077.     ULONG Signals;
  1078.  
  1079.     Signals=(1<<window->UserPort->mp_SigBit)|
  1080.             (1<<setupwindow->UserPort->mp_SigBit)|
  1081.             (1<<game_msg_port->mp_SigBit);
  1082. Wait:
  1083.     if(msg=GetMessage(window))      return(msg);
  1084.     if(msg=GetMessage(setupwindow)) return(msg);
  1085.     if(msg=GetJoy())                return(msg);
  1086.     Wait(Signals);
  1087.     goto Wait;
  1088. }
  1089.  
  1090. BOOL outside(BYTE x, BYTE y)
  1091. { /* ermittelt, ob x/y außerhalb des Spielfeldes liegt */
  1092.  
  1093.     if(x<0)     return(TRUE);
  1094.     if(x>=cols) return(TRUE);
  1095.     if(y<0)     return(TRUE);
  1096.     if(y>=rows) return(TRUE);
  1097.     return(FALSE);
  1098. }
  1099.  
  1100. BOOL included(struct Stein *stein, BYTE x, BYTE y)
  1101. { /* ermittelt, ob x/y vom Stein *stein (auf absolute Koordinaten
  1102.      umgerechnet !) bedeckt wird */
  1103.     BYTE cnt;
  1104.  
  1105.     if((x==stein->MitteX)&&(y==stein->MitteY))  return(TRUE);
  1106.     for(cnt=0;cnt<stein->Teile;++cnt)
  1107.         if((x==stein->OffsetX[cnt])&&(y==stein->OffsetY[cnt]))
  1108.             return(TRUE);
  1109.     return(FALSE);
  1110. }
  1111.  
  1112. BYTE collide(struct Stein *stein, BYTE spieler)
  1113. { /* ermittelt, ob der angegebene Stein für den angegebenen Spieler nicht
  1114.      existieren kann (die Spielenummer wird gebraucht, da
  1115.      aktueller_stein[spieler] im Gegensatz zu aktueller_stein[1-spieler]
  1116.      nicht zur Kollision herangezogen werden darf - es wird im Regelfall
  1117.      darum gehen, ob eine (noch nicht eingesetzte) Position erlaubt ist.
  1118.      Ergebnis:
  1119.      0 - keine Kollision
  1120.      1 - Kollision mit fest bestehenden Steinen / Lage außerhalb Spielfeld
  1121.      2 - Kollision mit anderem Spielstein
  1122.      Aus einem Ergebnis 1 folgt NICHT, daß der Stein sich nicht mit dem des
  1123.      Mitspielers überdeckt !                                            */
  1124.  
  1125.     BYTE x,y,cnt;
  1126.     struct Stein anderer_stein;
  1127.  
  1128.     x=stein->MitteX;
  1129.     y=stein->MitteY;
  1130.     if(outside(x,y))    return(1);
  1131.     if(Spielfeld[x][y]) return(1);
  1132.     for(cnt=0;cnt<stein->Teile;++cnt)
  1133.         {
  1134.         if(outside(x+stein->OffsetX[cnt],y+stein->OffsetY[cnt]))
  1135.             return(1);
  1136.         if(Spielfeld[x+stein->OffsetX[cnt]][y+stein->OffsetY[cnt]])
  1137.             return(1);
  1138.         }
  1139.     if(zwei_spieler)
  1140.         { /* Kollision mit anderem Stein ? */
  1141.         anderer_stein=aktueller_stein[1-spieler];
  1142.         /* Umrechnung auf absolute Koordinaten */
  1143.         x=anderer_stein.MitteX;
  1144.         y=anderer_stein.MitteY;
  1145.         for(cnt=0;cnt<stein->Teile;++cnt)
  1146.             {
  1147.             anderer_stein.OffsetX[cnt]+=x;
  1148.             anderer_stein.OffsetY[cnt]+=y;
  1149.             }
  1150.         /* eigentliche Kontrollen */
  1151.         if(included(&anderer_stein,x=stein->MitteX,y=stein->MitteY))
  1152.             return(2);
  1153.         for(cnt=0;cnt<stein->Teile;++cnt)
  1154.             if(included(&anderer_stein,x+stein->OffsetX[cnt],
  1155.                                        y+stein->OffsetY[cnt]))
  1156.                 return(2);
  1157.         }
  1158.     return(0);
  1159. }
  1160.  
  1161. BYTE Step(BYTE spieler, BYTE dx, BYTE dy)
  1162. { /* bewegt den Stein nach Möglichkeit.
  1163.      Ergebnis:
  1164.      0 - keine Kollision
  1165.      1 - Kollision mit fest bestehenden Steinen / Lage außerhalb Spielfeld
  1166.      2 - Kollision mit anderem Spielstein
  1167.      Aus einem Ergebnis 1 folgt NICHT, daß der Stein sich nicht mit dem des
  1168.      Mitspielers überdeckt !                                            */
  1169.  
  1170.     BYTE impossible;
  1171.     struct Stein *stein;
  1172.  
  1173.     stein=aktueller_stein+spieler;
  1174.     stein->MitteX+=dx;  stein->MitteY+=dy;
  1175.     impossible=collide(stein,spieler);
  1176.     stein->MitteX-=dx;  stein->MitteY-=dy;
  1177.     if(impossible)  return(impossible);
  1178.     ZeichneStein(stein,0);
  1179.     stein->MitteX+=dx;  stein->MitteY+=dy;
  1180.     ZeichneStein(stein,spieler+1);
  1181.     return(0);
  1182. }
  1183.  
  1184. #define Down(spieler) Step(spieler,0,1)
  1185.     /* bewegt den Stein nach Möglichkeit ein Feld abwärts.
  1186.        Returniert wird, ob's und weswegen es nicht ging. (^Step) */
  1187. #define Left(spieler) Step(spieler,-1,0)
  1188.     /* bewegt den Stein nach Möglichkeit ein Feld nach links. */
  1189. #define Right(spieler) Step(spieler,1,0)
  1190.     /* bewegt den Stein nach Möglichkeit ein Feld nach rechts. */
  1191.  
  1192. VOID Turn(BYTE spieler)
  1193. { /* den Stein des angegebenen Spielers wenn möglich drehen */
  1194.     UBYTE cnt,help;
  1195.     struct Stein old,*stein;
  1196.  
  1197.     stein=aktueller_stein+spieler;
  1198.     old=*stein;
  1199.     do  {
  1200.         /* Drehen */
  1201.         for(cnt=0;cnt<stein->Teile;++cnt)
  1202.             { /* ein Element drehen */
  1203.             help=stein->OffsetY[cnt];
  1204.             stein->OffsetY[cnt]=stein->OffsetX[cnt];
  1205.             stein->OffsetX[cnt]=-help;
  1206.             }
  1207.         } while(collide(stein,spieler));
  1208.             /* spätestens nach dem 4. Drehen bricht die Schleife ab: dann
  1209.                ist der Status Quo erreicht !                              */
  1210.     ZeichneStein(&old,0);
  1211.     ZeichneStein(stein,spieler+1);
  1212. }
  1213.  
  1214. VOID Mirror(BYTE spieler)
  1215. { /* den Stein des angegebenen Spielers wenn möglich senkrecht spiegeln */
  1216.     UBYTE cnt;
  1217.     struct Stein new,*stein;
  1218.  
  1219.     stein=aktueller_stein+spieler;
  1220.     new=*stein;
  1221.     for(cnt=0;cnt<stein->Teile;++cnt)   new.OffsetX[cnt]=-new.OffsetX[cnt];
  1222.     if(!collide(&new,spieler))
  1223.         {
  1224.         ZeichneStein(stein,0);
  1225.         *stein=new;
  1226.         ZeichneStein(stein,spieler+1);
  1227.         }
  1228. }
  1229.  
  1230. VOID Setzen(BYTE spieler)
  1231. { /* setzt den aktuellen_stein des angegebenen Spielers fest in das
  1232.      Spielfeld ein und handhabt alle Eventualitäten, inklusive Scoring. */
  1233.  
  1234.     struct Stein *stein;
  1235.     BYTE x,y,cnt;
  1236.  
  1237.     stein=aktueller_stein+spieler;
  1238.     x=stein->MitteX;
  1239.     y=stein->MitteY;
  1240.     Spielfeld[x][y]=spieler+1;
  1241.     ++Steine_Pro_Zeile[y];
  1242.     for(cnt=0;cnt<stein->Teile;++cnt)
  1243.         {
  1244.         Spielfeld[x+stein->OffsetX[cnt]][y+stein->OffsetY[cnt]]=spieler+1;
  1245.         ++Steine_Pro_Zeile[y+stein->OffsetY[cnt]];
  1246.         }
  1247.  
  1248.     /* Reihen überprüfen */
  1249.     for(cnt=0;cnt<rows;++cnt)
  1250.         if(Steine_Pro_Zeile[cnt]==cols)
  1251.             { /* Zeile einschmelzen */
  1252.             /* darüberliegende Zeilen runterholen */
  1253.             ++abgesenkte_zeilen;
  1254.             for(y=cnt-1;y>=0;--y)
  1255.                 {
  1256.                 for(x=0;x<cols;++x)
  1257.                     ZeichneSteinchen(Spielfeld[x][y+1]=Spielfeld[x][y],x,y+1);
  1258.                 Steine_Pro_Zeile[y+1]=Steine_Pro_Zeile[y];
  1259.                 }
  1260.             /* oberste Zeile löschen */
  1261.             for(x=0;x<cols;++x)
  1262.                 ZeichneSteinchen(Spielfeld[x][0]=0,x,0);
  1263.             Steine_Pro_Zeile[0]=0;
  1264.             if(!collided[1-spieler] && zwei_spieler)
  1265.                 ZeichneStein(aktueller_stein+1-spieler,2-spieler);
  1266.             }
  1267.  
  1268.     ++abgesetzte_steine[spieler];
  1269.     Scoring();
  1270. }
  1271.  
  1272. VOID Absetzen(BYTE spieler)
  1273. { /* den aktuellen_stein des genannten Spielers absenken, soweit möglich */
  1274.     BYTE help;
  1275.  
  1276.     while((help=Down(spieler))==0)  Delay(2);
  1277.     if(collided[spieler]=(help==1)) Setzen(spieler);
  1278. }
  1279.  
  1280. VOID Pause()
  1281. { /* Pause durchführen */
  1282.     static struct NewWindow pnw={0,0,240,11,-1,-1,
  1283.                                 IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_MOUSEBUTTONS,
  1284.                                 WFLG_ACTIVATE|WFLG_SMART_REFRESH|WFLG_RMBTRAP|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET,
  1285.                                 NULL,NULL,(UBYTE *)"Hybris V1.3 - Pause",
  1286.                                 NULL,NULL,5,5,640,256,WBENCHSCREEN};
  1287.     ULONG Signals;
  1288.  
  1289.     pnw.TopEdge=window->TopEdge+(window->Height-pnw.Height)/2;
  1290.     pnw.LeftEdge=window->LeftEdge+(window->Width-pnw.Width)/2;
  1291.     if(pnw.LeftEdge<0)  pnw.LeftEdge=0;
  1292.     pnw.Screen=window->WScreen;
  1293.     if(!(pausewindow=OpenWindow(&pnw))) return; /* kein Window zu haben */
  1294.     ScratchMsgQueue(window->UserPort);
  1295.     ScratchMsgQueue(setupwindow->UserPort);
  1296.     /* (möglichst) die RAWKEY-KeyUp-Message bei Tastatur-Pause abfangen */
  1297.     Delay(10);  ScratchMsgQueue(pausewindow->UserPort);
  1298.     while(GetJoy());
  1299.     Signals=(1<<pausewindow->UserPort->mp_SigBit)|
  1300.             (1<<setupwindow->UserPort->mp_SigBit)|
  1301.             (1<<game_msg_port->mp_SigBit);
  1302.     do  {
  1303.         /* ggf. Refresh durchführen lassen */
  1304.         while(GetMessage(setupwindow));
  1305.         /* bei relevanten Messages Abbruch der Pause */
  1306.         if(GetMessage(pausewindow)) break;
  1307.         if(GetJoy())                break;
  1308.         Wait(Signals);
  1309.         } while(TRUE);
  1310.     Forbid();
  1311.     ScratchMsgQueue(pausewindow->UserPort);
  1312.     CloseWindow(pausewindow);
  1313.     pausewindow=NULL;
  1314.     Permit();
  1315.     ScratchMsgQueue(window->UserPort);
  1316.     ScratchMsgQueue(setupwindow->UserPort);
  1317.     while(GetJoy());
  1318. }
  1319.  
  1320. VOID main()
  1321. {
  1322.     struct IntuiMessage *msg;
  1323.     BYTE x,y;
  1324.     short cnt;
  1325.  
  1326.     rows=20;
  1327.     cols=11;
  1328.     preview=spiel_laeuft=zwei_spieler=FALSE;
  1329.     FallDelay=3;
  1330.     for(cnt=1;cnt<8;++cnt)  betonungen[cnt]=0;
  1331.     init();
  1332.     wechsle_betonung(4,1);
  1333.  
  1334.     while(TRUE)
  1335.         {
  1336.         /* neues Spiel vorbereiten */
  1337.         spiel_laeuft=FALSE;
  1338.         start=FALSE;
  1339.         ActivateWindow(setupwindow);
  1340.         WindowToFront(setupwindow);
  1341.         GT_SetGadgetAttrsA(Gadgets[0],setupwindow,NULL,TAGA_ENABLE);
  1342.         GT_SetGadgetAttrsA(Gadgets[1],setupwindow,NULL,TAGA_ENABLE);
  1343.         GT_SetGadgetAttrsA(Gadgets[3],setupwindow,NULL,TAGA_ENABLE);
  1344.         if(anzahl_erlaubter_steine)
  1345.             GT_SetGadgetAttrsA(Gadgets[4],setupwindow,NULL,TAGA_ENABLE);
  1346.         GT_SetGadgetAttrsA(Gadgets[12],setupwindow,NULL,TAGA_ENABLE);
  1347.         while(!start)
  1348.             {
  1349.             msg=WaitMessage();
  1350.             if(msg->Class==IDCMP_JOY)   start=(BOOL)msg->Qualifier;
  1351.             }
  1352.         GT_SetGadgetAttrsA(Gadgets[0],setupwindow,NULL,TAGA_DISABLE);
  1353.         GT_SetGadgetAttrsA(Gadgets[1],setupwindow,NULL,TAGA_DISABLE);
  1354.         GT_SetGadgetAttrsA(Gadgets[3],setupwindow,NULL,TAGA_DISABLE);
  1355.         GT_SetGadgetAttrsA(Gadgets[4],setupwindow,NULL,TAGA_DISABLE);
  1356.         GT_SetGadgetAttrsA(Gadgets[12],setupwindow,NULL,TAGA_DISABLE);
  1357.         ClearGamblingArea();
  1358.         for(y=0;y<rows;++y)
  1359.             {
  1360.             for(x=0;x<cols;++x)     Spielfeld[x][y]=0;
  1361.             Steine_Pro_Zeile[y]=0;
  1362.             }
  1363.         abgesetzte_steine[0]=abgesetzte_steine[1]=abgesenkte_zeilen=0;
  1364.         Scoring();
  1365.         spiel_laeuft=TRUE;
  1366.         abort=FALSE;
  1367.         ActivateWindow(window);
  1368.         WindowToFront(window);
  1369.  
  1370.         /* erste Steine anmahnen: */
  1371.         collided[0]=TRUE;
  1372.         collided[1]=zwei_spieler;   /* 2. Spieler kriegt nur einen Stein,
  1373.                                        wenn er überhaupt mitspielt */
  1374.         while(!abort)
  1375.             {
  1376.             if(collided[0])
  1377.                 { /* Stein für Spieler 1 ins Spiel bringen */
  1378.                 aktueller_stein[0]=naechster_stein[0];
  1379.                 Preview(0);
  1380.                 /* Steine[erlaubte_steine[
  1381.                                           RangeRand(anzahl_erlaubter_steine)
  1382.                                          ] ]; */
  1383.                 /*if(zwei_spieler)    aktueller_stein[0].MitteX-=2;*/
  1384.                 if(!(collided[0]=collide(aktueller_stein,0)))
  1385.                     ZeichneStein(aktueller_stein,1);
  1386.                 }
  1387.             if(collided[1] && zwei_spieler)
  1388.                 { /* Stein für Spieler 2 ins Spiel bringen */
  1389.                 aktueller_stein[1]=naechster_stein[1];
  1390.                 Preview(1);
  1391.                 /* Steine[erlaubte_steine[
  1392.                                           RangeRand(anzahl_erlaubter_steine)
  1393.                                          ] ]; */
  1394.                 /*aktueller_stein[1].MitteX+=2;*/
  1395.                 if(!(collided[1]=collide(aktueller_stein+1,1)))
  1396.                     ZeichneStein(aktueller_stein+1,2);
  1397.                 }
  1398.             abort=collided[0] && (collided[1] || !zwei_spieler);
  1399.             msg=WaitMessage();
  1400.             switch(msg->Class)
  1401.                 {
  1402.                 case IDCMP_INTUITICKS:
  1403.                     for(cnt=0;cnt<=zwei_spieler;++cnt)
  1404.                         if(!collided[cnt])
  1405.                             if(collided[cnt]=(Down(cnt)==1))    Setzen(cnt);
  1406.                     break;
  1407.                 case IDCMP_JOY:
  1408.                     if(msg->Qualifier)
  1409.                         Turn(0);
  1410.                     else if(msg->MouseY==0)
  1411.                         {
  1412.                         if(msg->MouseX)
  1413.                             Step(0,msg->MouseX,0);
  1414.                         }
  1415.                     else if(msg->MouseX==0)
  1416.                         {
  1417.                         if(msg->MouseY>0)
  1418.                             {
  1419.                             Absetzen(0);
  1420.                             /* gepufferte Kommandos löschen */
  1421.                             while(GetJoy());
  1422.                             }
  1423.                         else if(msg->MouseY<0)
  1424.                             Pause();
  1425.                         }
  1426.                     break;
  1427.                 case IDCMP_VANILLAKEY:
  1428.                     if(msg->IDCMPWindow==window)
  1429.                         switch(msg->Code)
  1430.                             {
  1431.                             case '2':   /* runter */
  1432.                                         Absetzen(zwei_spieler);
  1433.                                         /* gepufferte Kommandos löschen */
  1434.                                         ScratchMsgQueue(window->UserPort);
  1435.                                         break;
  1436.                             case '6':   /* rechts */
  1437.                                         Right(zwei_spieler);    break;
  1438.                             case '4':   /* links */
  1439.                                         Left(zwei_spieler);     break;
  1440.                             case 'p':
  1441.                             case 'P':
  1442.                             case '8':   Pause();                break;
  1443.                             case ' ':
  1444.                             case '5':
  1445.                             case 10:    /* LF */
  1446.                             case 13:    /* CR */
  1447.                                         Turn(zwei_spieler);     break;
  1448.                             case 'm':
  1449.                             case 'M':   Mirror(zwei_spieler);   break;
  1450.                             }
  1451.                     break;
  1452.                 case IDCMP_RAWKEY:
  1453.                     switch(msg->Code)
  1454.                         {
  1455.                         case 0x4d: /* runter */
  1456.                             Absetzen(zwei_spieler);
  1457.                             /* gepufferte Kommandos löschen */
  1458.                             ScratchMsgQueue(window->UserPort);
  1459.                             break;
  1460.                         case 0x4e:  /* rechts */
  1461.                                     Right(zwei_spieler);
  1462.                                     break;
  1463.                         case 0x4f:  /* links */
  1464.                                     Left(zwei_spieler);
  1465.                                     break;
  1466.                         case 0x4c:  /* rauf */
  1467.                         case 0x5f:  Pause();
  1468.                                     break;
  1469.                         }
  1470.                     break;
  1471.                 }
  1472.             }
  1473.         ScratchMsgQueue(window->UserPort);
  1474.         spiel_laeuft=FALSE;
  1475.         }
  1476. }
  1477.  
  1478. void wbmain(struct WBStartup *wbarg)
  1479. { main(); }
  1480.